﻿using System;
using System.Globalization;

namespace H.Types
{
    /// <summary>
    /// 表示一个RGB颜色(24位)
    /// </summary>
    [Serializable]
    public struct RGB
    {
        /// <summary>
        /// 内部存储颜色值的红色分量
        /// </summary>
        private byte _r;

        /// <summary>
        /// 内部存储颜色值的绿色分量
        /// </summary>
        private byte _g;

        /// <summary>
        /// 内部存储颜色值的蓝色分量
        /// </summary>
        private byte _b;

        /// <summary>
        /// 内部存储颜色值字符串
        /// </summary>
        private string _rgb;

        /// <summary>
        /// 读取或设置红色分量
        /// </summary>
        public byte R
        {
            get => _r;
            set { _r = value; _rgb = ValRGB.ToString("X6"); }
        }

        /// <summary>
        /// 读取或设置绿色分量
        /// </summary>
        public byte G
        {
            get => _g;
            set { _g = value; _rgb = ValRGB.ToString("X6"); }
        }

        /// <summary>
        /// 读取或设置蓝色分量
        /// </summary>
        public byte B
        {
            get => _b;
            set { _b = value; _rgb = ValRGB.ToString("X6"); }
        }

        /// <summary>
        /// 读取或设置颜色值,如果颜色值不合法,则会抛出FormatException异常
        /// </summary>
        /// <exception cref="FormatException">当颜色值不合法时抛出</exception>
        public string StrRGB
        {
            get => _rgb ?? throw new InvalidOperationException("颜色未初始化,无法读取");
            set
            {
                if (SetRGB(value, out _r, out _g, out _b))
                {
                    _rgb = value;
                }
                else
                {
                    throw new FormatException("颜色值格式不合法");
                }
            }
        }

        /// <summary>
        /// 计算RGB的颜色值(数字表示)
        /// </summary>
        public int ValRGB => _r << 16 | _g << 8 | _b;

        /// <summary>
        /// 表示黑色或者零偏色
        /// </summary>
        public static readonly RGB Black = new RGB(0);

        /// <summary>
        /// 初始化一个颜色
        /// </summary>
        /// <param name="rgb"></param>
        public RGB(string rgb)
        {
            if (SetRGB(rgb, out _r, out _g, out _b))
            {
                _rgb = rgb;
            }
            else
            {
                throw new FormatException("颜色值格式不合法");
            }
        }

        /// <summary>
        /// 初始化一个颜色
        /// </summary>
        /// <param name="rgb"></param>
        public RGB(int rgb)
        {
            uint result = (uint)(rgb & 0xFFFFFF);
            _r = (byte)((result >> 16) & 0XFF);
            _g = (byte)((result >> 8) & 0XFF);
            _b = (byte)(result & 0XFF);
            _rgb = (_r << 16 | _g << 8 | _b).ToString("X6");
        }

        /// <summary>
        /// 初始化一个颜色
        /// </summary>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        public RGB(byte r, byte g, byte b)
        {
            _r = r;
            _g = g;
            _b = b;
            _rgb = (_r << 16 | _g << 8 | _b).ToString("X6");
        }

        /// <summary>
        /// 将一个RGB字符串转换为对应的分量
        /// </summary>
        /// <param name="rgb">输入的RGB字符串(十六进制)</param>
        /// <param name="r">红色分量</param>
        /// <param name="g">绿色分量</param>
        /// <param name="b">蓝色份量</param>
        /// <returns></returns>
        public static bool SetRGB(string rgb, out byte r, out byte g, out byte b)
        {
            if (uint.TryParse(rgb, NumberStyles.HexNumber, NumberFormatInfo.CurrentInfo, out uint result))
            {
                r = (byte)((result >> 16) & 0XFF);
                g = (byte)((result >> 8) & 0XFF);
                b = (byte)(result & 0XFF);
                return true;
            }
            else
            {
                r = g = b = 0;
                return false;
            }
        }


        /// <summary>
        /// 打印颜色值
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return _rgb;
        }
    }
}
